<!--
 * @Author: Ethan Teng
 * @Date: 2022-08-13 12:58:05
 * @LastEditTime: 2022-08-19 14:17:13
 * @Description: 
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Hello World</h1>

    <script>
      const imgRequest = (url, data) => {
        if (!url || !data) return;

        const img = new Image();

        img.onload = () => {
          console.log('loaded...');
        };

        img.onerror = () => {
          console.log('error....');
        };

        img.src = `${url}${url.indexOf('?') < 0 ? '?' : '&'}${encodeURIComponent(
          JSON.stringify(data)
        )}`;
      };

      const beaconRequest = (url, data) => {
        if (!url || !data) return;

        // OK
        // application/x-www-form-urlencoded
        // const param = new URLSearchParams({
        //   data: JSON.stringify(data)
        // });

        // OK
        // 'content-type': 'application/x-www-form-urlencoded',
        const param = new Blob([JSON.stringify(data)], {
          type: 'application/x-www-form-urlencoded'
        });

        // bug
        // multipart/form-data
        // const param = new FormData();
        // param.append('key', 'hello');
        // param.append('value', 'hello');

        // bug
        // application/json
        // const param = new Blob([JSON.stringify(data)], {
        //   type: 'application/json'
        // });

        // bug
        // const param = new Blob([JSON.stringify(data)], {
        //   type: 'text/plain;charset=utf-8'
        // });

        // bug
        // const param = JSON.stringify(data);

        navigator.sendBeacon(url, param);
      };

      const ajaxRequest = (url, data) => {
        if (!url || !data) return;

        const client = new XMLHttpRequest();
        client.open('POST', url, false);
        client.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
        client.setRequestHeader('Access-Control-Allow-Origin', '*');
        client.send(JSON.stringify(data));
      };

      const upload = (url, data) => {
        const len = `${url}${url.indexOf('?') < 0 ? '?' : '&'}${encodeURIComponent(
          JSON.stringify(data)
        )}`.length;

        // 2083 compatible with ie browser
        // chrome 8182
        // safari 80000
        // firefox 65536
        // opera 190000
        if (len < 2083) {
          imgRequest(url, data);
        } else if (window.navigator.sendBeacon) {
          beaconRequest(url, data);
        } else {
          ajaxRequest(url, data);
        }
      };

      // ---------------------------

      const start = () => {
        const source = new EventSource('http://localhost:3001/get-data');

        source.addEventListener(
          'open',
          () => {
            console.log('SSE connection established');
          },
          false
        );

        source.addEventListener(
          'message',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );

        return source;
      };

      const testPlatformInfo = () => {
        const source = start();
        source.addEventListener(
          'device-info',
          e => {
            console.log(`device-info: ${e.data}`);
          },
          false
        );
        source.addEventListener(
          'page-info',
          e => {
            console.log(`page-info: ${e.data}`);
          },
          true
        );

        upload('http://localhost:3001/platform-info/empty.gif', {
          type: 'device-info',
          time: Date.now(),
          value: {
            origin: 'http://localhost:3000',
            url: 'http://localhost:3000/#/page2',
            title: 'Vite + Vue + TS',
            referer: 'http://localhost:3000/',
            os: {
              type: 'xxxxxxxxMacOs',
              version: ''
            },
            browser: {
              type: 'Chrome',
              version: '103.0.0.0'
            },
            language: 'zh-CN'
          }
        });
      };

      const testPerformanceTiming = () => {
        const source = start();
        source.addEventListener(
          'performance-timing',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );

        upload('http://localhost:3001/performance-timing/empty.gif', {
          type: 'first-input-delay',
          time: Date.now(),
          value: {
            value: 40397.2,
            delay: 4.4,
            eventHandleTime: 0
          }
        });

        upload('http://localhost:3001/performance-timing/empty.gif', {
          type: 'first-paint',
          time: Date.now(),
          value: 98.4
        });
      };

      const testNavigationTiming = () => {
        const source = start();
        source.addEventListener(
          'navigation-timing',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );

        upload('http://localhost:3001/navigation-timing/empty.gif', {
          type: 'navigation-timing',
          time: Date.now(),
          value: {
            redirect: 0,
            DNS: 0,
            TCP: 0,
            SSL: 0,
            TTFB: 2,
            transmit: 3.2,
            domParse: 77.3,
            deferExecuteDuration: 26.6,
            domContentLoadedCallback: 0.1,
            resourceLoad: 12.8,
            domReady: 117.2,
            L: 130
          }
        });
      };

      const testResourceFlow = () => {
        const source = start();
        source.addEventListener(
          'resource-flow',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );

        ajaxRequest('http://localhost:3001/resource-flow/add', {
          type: 'resource-flow',
          time: Date.now(),
          value: [
            {
              name: 'http://localhost:3000/@vite/client',
              time: Date.now(),
              transferSize: 300,
              initiatorType: 'script',
              startTime: 28.9,
              responseEnd: 38.1,
              DNS: 0,
              initialConnect: 0,
              SSL: 28.9,
              request: 0.9,
              TTFB: 0.9,
              transmit: 0.3,
              contentDownload: 0.9
            },
            {
              name: 'https://img1.baidu.com/it/u=3217543765,3223180824&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=750',
              time: Date.now(),
              transferSize: 0,
              initiatorType: 'img',
              startTime: 29,
              responseEnd: 35.5,
              DNS: 0,
              initialConnect: 0,
              SSL: 0,
              request: 2.5,
              TTFB: 2.5,
              transmit: 2,
              contentDownload: 2.5
            },
            {
              name: 'https://img0.baidu.com/it/u=2518378277,1696634197&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=773',
              time: Date.now(),
              transferSize: 0,
              initiatorType: 'img',
              startTime: 29.2,
              responseEnd: 97.7,
              DNS: 0,
              initialConnect: 0,
              SSL: 0,
              request: 0.3,
              TTFB: 0.3,
              transmit: 0.4,
              contentDownload: 0.3
            },
            {
              name: 'http://localhost:3000/src/main.ts?t=1659594691863',
              time: Date.now(),
              transferSize: 1148,
              initiatorType: 'script',
              startTime: 29.3,
              responseEnd: 100.9,
              DNS: 0,
              initialConnect: 0,
              SSL: 29.3,
              request: 4.5,
              TTFB: 4.5,
              transmit: 0.3,
              contentDownload: 4.5
            },
            {
              name: 'http://localhost:3000/node_modules/.pnpm/registry.npmmirror.com+vite@3.0.4/node_modules/vite/dist/client/env.mjs',
              time: Date.now(),
              transferSize: 300,
              initiatorType: 'other',
              startTime: 97.2,
              responseEnd: 99.1,
              DNS: 0,
              initialConnect: 0,
              SSL: 97.2,
              request: 0.6,
              TTFB: 0.6,
              transmit: 0.2,
              contentDownload: 0.6
            }
          ]
        });
      };

      const testUserBehavior = () => {
        const source = start();
        source.addEventListener(
          'router-change',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );
        source.addEventListener(
          'http',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );
        source.addEventListener(
          'operation',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );

        ajaxRequest('http://localhost:3001/user-behavior/add', {
          time: Date.now(),
          value: [
            {
              type: 'router-change',
              page: 'http://localhost:3000/#/page2',
              time: Date.now(),
              detail: {
                method: 'Hash',
                href: 'http://localhost:3000/#/page2',
                hash: '#/page2'
              }
            },
            {
              type: 'router-change',
              page: 'http://localhost:3000/#/page1',
              time: Date.now(),
              detail: {
                method: 'Hash',
                href: 'http://localhost:3000/#/page1',
                hash: '#/page1'
              }
            },
            {
              type: 'router-change',
              page: 'http://localhost:3000/page1',
              time: Date.now(),
              detail: {
                method: 'History',
                href: 'http://localhost:3000/page1',
                pathname: '/page1'
              }
            },
            {
              type: 'router-change',
              page: 'http://localhost:3000/page2',
              time: Date.now(),
              detail: {
                method: 'History',
                href: 'http://localhost:3000/page2',
                pathname: '/page2'
              }
            }
          ]
        });

        ajaxRequest('http://localhost:3001/user-behavior/add', {
          time: Date.now(),
          value: [
            {
              type: 'request',
              page: '',
              time: Date.now(),
              detail: {
                method: 'GET',
                url: 'http://localhost:8080/api/get-name',
                headers: {
                  Accept: 'application/json, text/plain, */*',
                  Cache: 'no-cache'
                },
                body: '',
                status: 0,
                statusText: '',
                requestTime: 72.19999992847443,
                responseTime: 76.39999997615814,
                response: ''
              }
            },
            {
              type: 'request',
              page: '',
              time: Date.now(),
              detail: {
                method: 'GET',
                url: 'http://localhost:8080/api/fetch-get',
                headers: {},
                body: '',
                status: 0,
                statusText: '',
                requestTime: 72.60000002384186,
                responseTime: 0,
                response: ''
              }
            }
          ]
        });

        ajaxRequest('http://localhost:3001/user-behavior/add', {
          time: Date.now(),
          value: [
            {
              type: 'operation',
              page: '',
              time: Date.now(),
              detail: {
                type: 'click',
                target: {},
                count: 1,
                id: 'ipt',
                classList: [],
                tagName: 'input',
                innerText: ''
              }
            },
            {
              type: 'operation',
              page: '',
              time: Date.now(),
              detail: {
                type: 'keydown',
                target: {},
                count: 13,
                id: 'ipt',
                classList: [],
                tagName: 'input',
                innerText: ' [Shift] Hello  [Shift] World'
              }
            },
            {
              type: 'operation',
              page: '',
              time: Date.now(),
              detail: {
                type: 'click',
                target: {},
                count: 7,
                id: 'btn',
                classList: ['hello', 'world', 'this', 'is', 'a', 'className'],
                tagName: 'button',
                innerText: ' button click click'
              }
            }
          ]
        });
      };

      const testErrorInfo = () => {
        const source = start();
        source.addEventListener(
          'stack-trace',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );
        source.addEventListener(
          'js-error',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );
        source.addEventListener(
          'resource-error',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );
        source.addEventListener(
          'http-error',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );
        source.addEventListener(
          'cors-error',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );

        upload('http://localhost:3001/error-info/empty.gif', {
          type: 'js',
          errorUid:
            'anMtVW5jYXVnaHQlMjBFcnJvciUzQSUyMHRoaXMlMjBpcyUyMGElMjBFcnJvci1odHRwJTNBJTJGJTJGbG9jYWxob3N0JTNBMzAwMCUyRnNyYyUyRnRlc3QudHM=',
          time: Date.now(),
          message: 'Uncaught Error: this is a Error',
          detail: {
            type: 'Error',
            stackTrace: [
              {
                filename: 'http://localhost:3000/src/test.ts',
                functionName: 't',
                line: 2,
                col: 9
              },
              {
                filename: 'http://localhost:3000/src/main.ts?t=1660205635051',
                functionName: '',
                line: 14,
                col: 3
              }
            ]
          }
        });

        upload('http://localhost:3001/error-info/empty.gif', {
          type: 'unhandledrejection',
          errorUid:
            'dW5oYW5kbGVkcmVqZWN0aW9uLUVycm9yJTNBJTIwVGhpcyUyMGlzJTIwYSUyMHByb21pc2UlMjByZWplY3Rpb24tRXJyb3I=',
          time: Date.now(),
          message: {},
          detail: {
            type: {},
            stackTrace: [
              {
                filename: 'http://localhost:3000/src/test.ts?t=1660205726302',
                functionName: '',
                line: 3,
                col: 12
              },
              {
                filename: '<anonymous>',
                functionName: 'new Promise',
                line: null,
                col: null
              },
              {
                filename: 'http://localhost:3000/src/test.ts?t=1660205726302',
                functionName: 't',
                line: 2,
                col: 3
              },
              {
                filename: 'http://localhost:3000/src/main.ts?t=1660205726302',
                functionName: '',
                line: 14,
                col: 3
              }
            ]
          }
        });

        upload('http://localhost:3001/error-info/empty.gif', {
          type: 'resource',
          errorUid: 'cmVzb3VyY2UtaHR0cCUzQSUyRiUyRnRoaXNpc2FlcnJvcmltZy5jb20lMkZlcnJvckltZy1JTUc=',
          time: 6944.0999999940395,
          message: '',
          detail: {
            type: 'Unknwon',
            src: 'http://thisisaerrorimg.com/errorImg',
            outerHTML: '<img src="http://thisisaerrorimg.com/errorImg" alt="img">',
            tagName: 'IMG'
          }
        });

        upload('http://localhost:3001/error-info/empty.gif', {
          type: 'http',
          errorUid:
            'anMtVW5jYXVnaHQlMjBFcnJvciUzQSUyMHRoaXMlMjBpcyUyMGElMjBFcnJvci1odHRwJTNBJTJGJTJGbG9jYWxob3N0JTNBMzAwMCUyRnNyYyUyRnRlc3QudHM=',
          time: 3127.7000000029802,
          message: 'xxxxxxx',
          detail: {
            status: 404,
            response: '',
            statusText: 'Not Found'
          }
        });

        upload('http://localhost:3001/error-info/empty.gif', {
          type: 'cors',
          errorUid:
            'anMtVW5jYXVnaHQlMjBFcnJvciUzQSUyMHRoaXMlMjBpcyUyMGElMjBFcnJvci1odHRwJTNBJTJGJTJGbG9jYWxob3N0JTNBMzAwMCUyRnNyYyUyRnRlc3QudHM=',
          time: 3127.7000000029802,
          message: '',
          detail: {
            tagName: 'script'
          }
        });
      };

      const testVisitInfo = () => {
        const source = start();
        source.addEventListener(
          'visit-info',
          e => {
            console.log(`message: ${e.data}`);
          },
          false
        );

        upload('http://localhost:3001/visit-info/empty.gif', {
          time: Date.now(),
          origin: 'http://baidu.com',
          type: 'normal'
        });
      };

      // testPlatformInfo();
      // testPerformanceTiming();
      // testNavigationTiming();
      // testResourceFlow();
      // testUserBehavior();
      // testErrorInfo();
      // testVisitInfo();
    </script>
  </body>
</html>
